# cronmon - Cron e-mail filtering and management
# Copyright (c) 2010 Crown copyright
# 
# This file is part of cronmon.
# 
# cronmon is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# cronmon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with cronmon.  If not, see <http://www.gnu.org/licenses/>.

import re
from django.db import models


class EnabledManager(models.Manager):
    """A manager able to select only objects that are enabled."""
    def enabled(self):
        return self.filter(enabled=True)

    def disabled(self):
        return self.filter(disabled=True)
    

class TagMatch(models.Model):
    """A rule to apply a tag to a message"""
    tag = models.SlugField()
    match_in = models.CharField(max_length=1, choices=[('S', 'Subject'), ('B', 'Body'), ('H', 'Hostname'), ('L', 'Last Line')])
    regex = models.TextField()
    dotall = models.BooleanField()
    multiline = models.BooleanField()
    caseinsensitive = models.BooleanField(default=True)

    enabled = models.BooleanField(default=True, db_index=True)

    objects = EnabledManager()

    def compile(self):
        try:
            return self._re
        except AttributeError:
            flags = 0
            if self.dotall:
                flags |= re.S
            if self.multiline:
                flags |= re.M
            if self.caseinsensitive:
                flags |= re.I

            self._re = re.compile(self.regex, flags)
            return self._re

    def match(self, message, body=None):
        regex = self.compile()

        if body is None:
            body = message.text_body()

        if self.match_in == 'H':
            return bool(regex.search(message.host.name))

        if self.match_in == 'S':
            return bool(regex.search(message.subject))

        if self.match_in == 'B':
            return bool(regex.search(body))

        if self.match_in == 'L':
            lines = [l for l in body.split('\n') if l.strip()]
            if not lines:
                return False
            return bool(regex.search(lines[-1]))

    def __unicode__(self):
        return self.tag

    class Meta:
        verbose_name_plural = "tag matches"

ACTIONS = [
    ('1', 'Set importance Notice', 'Importance set to Notice'),
    ('2', 'Set importance Warning', 'Importance set to Warning'),
    ('3', 'Set importance Critical', 'Importance set to Critical'),
    ('L', 'Keep only latest from each host', 'Replaced similar messages'),
    ('E', 'Escalate to RT', 'Escalated to RT'),
    ('I', 'Discard', 'Discarded'),
]

class Action(models.Model):
    """An action to take when a set of tags match on a message"""
    name = models.CharField(max_length=255)
    filter = models.TextField()
    action = models.CharField(max_length=1, choices=[a[:2] for a in ACTIONS]) 
    priority = models.FloatField(default=10.0)

    enabled = models.BooleanField(default=True, db_index=True)

    objects = EnabledManager()

    def __unicode__(self):
        return self.name

    def parse_filter(self):
        from actions import RuleParser
        parser = RuleParser()
        return parser.parse(self.filter)

    def apply_action(self, message):
        action = self.get_action_display().lower().replace(' ', '_')
        getattr(self, action)(message)

        for action, display_name, past_name in ACTIONS:
            if action == self.action:
                message.add_log_message("%s by action '%s'" % (past_name, self.name), type='filter')
                break

    def set_importance_notice(self, message):
        message.importance = 1
        message.save()

    def set_importance_warning(self, message):
        message.importance = 2
        message.save()

    def set_importance_critical(self, message):
        message.importance = 3
        message.save()

    def keep_only_latest_from_each_host(self, message):
        raise NotImplementedError("keep_only_latest_from_each_host")

    def escalate_to_rt(self, message):
        from cronmon.cron.escalation import escalate
        escalate(message)

    def discard(self, message):
        message.discard()
